package com.blog.cmrpersonalblog.controller;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.blog.cmrpersonalblog.common.Result;
import com.blog.cmrpersonalblog.dto.notification.requset.NotificationQueryRequest;
import com.blog.cmrpersonalblog.dto.notification.respnose.NotificationGroupResponse;
import com.blog.cmrpersonalblog.dto.notification.respnose.NotificationResponse;
import com.blog.cmrpersonalblog.dto.notification.respnose.NotificationStatsResponse;
import com.blog.cmrpersonalblog.service.NotificationService;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 通知控制器
 */
@Slf4j
@RestController
@RequestMapping("/api/notifications")
public class NotificationController {

    @Resource
    private NotificationService notificationService;

    /**
     * 分页查询通知列表（默认只返回内容型通知）
     * 
     * <p>默认行为：</p>
     * <ul>
     *   <li>当 type 参数为空时，只返回内容型通知（COMMENT、REPLY、MENTION、SYSTEM）</li>
     *   <li>可聚合类型（LIKE、FOLLOW、COLLECT）请使用 /api/notifications/grouped 接口</li>
     *   <li>如果需要查询特定类型，可通过 type 参数指定（包括可聚合类型）</li>
     * </ul>
     * 
     * <p>返回的通知类型：</p>
     * <ul>
     *   <li>COMMENT - 评论通知（包含详细评论内容）</li>
     *   <li>REPLY - 回复通知（包含回复内容和原评论）</li>
     *   <li>MENTION - @提及通知（包含提及上下文）</li>
     *   <li>SYSTEM - 系统通知</li>
     * </ul>
     *
     * @param query 查询条件 (type为空时默认排除LIKE/FOLLOW/COLLECT)
     * @return 通知分页列表
     */
    @GetMapping("/list")
    @SaCheckLogin
    public Result<IPage<NotificationResponse>> getNotificationList(@Valid NotificationQueryRequest query) {
        try {
            Long userId = StpUtil.getLoginIdAsLong();
            IPage<NotificationResponse> page = notificationService.getNotificationPage(userId, query);
            return Result.success("查询成功", page);
        } catch (Exception e) {
            log.error("查询通知列表失败", e);
            return Result.error("查询失败：" + e.getMessage());
        }
    }

    /**
     * 获取通知详情
     *
     * @param notificationId 通知ID
     * @return 通知详情
     */
    @GetMapping("/{notificationId}")
    @SaCheckLogin
    public Result<NotificationResponse> getNotificationDetail(@PathVariable Long notificationId) {
        try {
            Long userId = StpUtil.getLoginIdAsLong();
            NotificationResponse response = notificationService.getNotificationDetail(notificationId, userId);
            
            // 自动标记为已读
            notificationService.markAsRead(notificationId, userId);
            
            return Result.success("查询成功", response);
        } catch (Exception e) {
            log.error("获取通知详情失败: notificationId={}", notificationId, e);
            return Result.error("获取详情失败：" + e.getMessage());
        }
    }

    /**
     * 获取用户通知统计
     *
     * @return 通知统计
     */
    @GetMapping("/stats")
    @SaCheckLogin
    public Result<NotificationStatsResponse> getNotificationStats() {
        try {
            Long userId = StpUtil.getLoginIdAsLong();
            NotificationStatsResponse stats = notificationService.getNotificationStats(userId);
            return Result.success("查询成功", stats);
        } catch (Exception e) {
            log.error("获取通知统计失败", e);
            return Result.error("查询失败：" + e.getMessage());
        }
    }

    /**
     * 获取最新通知列表
     *
     * @param limit 限制数量
     * @return 通知列表
     */
    @GetMapping("/latest")
    @SaCheckLogin
    public Result<List<NotificationResponse>> getLatestNotifications(
            @RequestParam(defaultValue = "10") Integer limit) {
        try {
            Long userId = StpUtil.getLoginIdAsLong();
            List<NotificationResponse> notifications = notificationService.getLatestNotifications(userId, limit);
            return Result.success("查询成功", notifications);
        } catch (Exception e) {
            log.error("获取最新通知失败", e);
            return Result.error("查询失败：" + e.getMessage());
        }
    }

    /**
     * 标记通知为已读
     *
     * @param notificationId 通知ID
     * @return 操作结果
     */
    @PutMapping("/{notificationId}/read")
    @SaCheckLogin
    public Result<String> markAsRead(@PathVariable Long notificationId) {
        try {
            Long userId = StpUtil.getLoginIdAsLong();
            boolean success = notificationService.markAsRead(notificationId, userId);
            return success ? Result.success("标记成功") : Result.error("标记失败");
        } catch (Exception e) {
            log.error("标记通知为已读失败: notificationId={}", notificationId, e);
            return Result.error("标记失败：" + e.getMessage());
        }
    }

    /**
     * 批量标记通知为已读
     *
     * @param notificationIds 通知ID列表
     * @return 操作结果
     */
    @PutMapping("/batch-read")
    @SaCheckLogin
    public Result<String> batchMarkAsRead(@RequestBody List<Long> notificationIds) {
        try {
            Long userId = StpUtil.getLoginIdAsLong();
            boolean success = notificationService.batchMarkAsRead(notificationIds, userId);
            return success ? Result.success("批量标记成功") : Result.error("批量标记失败");
        } catch (Exception e) {
            log.error("批量标记通知为已读失败", e);
            return Result.error("批量标记失败：" + e.getMessage());
        }
    }

    /**
     * 标记所有通知为已读
     *
     * @param type 通知类型（可选）
     * @return 操作结果
     */
    @PutMapping("/read-all")
    @SaCheckLogin
    public Result<String> markAllAsRead(@RequestParam(required = false) String type) {
        try {
            Long userId = StpUtil.getLoginIdAsLong();
            boolean success = notificationService.markAllAsRead(userId, type);
            return success ? Result.success("全部标记成功") : Result.error("全部标记失败");
        } catch (Exception e) {
            log.error("标记所有通知为已读失败", e);
            return Result.error("全部标记失败：" + e.getMessage());
        }
    }

    /**
     * 删除通知
     *
     * @param notificationId 通知ID
     * @return 操作结果
     */
    @DeleteMapping("/{notificationId}")
    @SaCheckLogin
    public Result<String> deleteNotification(@PathVariable Long notificationId) {
        try {
            Long userId = StpUtil.getLoginIdAsLong();
            boolean success = notificationService.deleteNotification(notificationId, userId);
            return success ? Result.success("删除成功") : Result.error("删除失败");
        } catch (Exception e) {
            log.error("删除通知失败: notificationId={}", notificationId, e);
            return Result.error("删除失败：" + e.getMessage());
        }
    }

    /**
     * 批量删除通知
     *
     * @param notificationIds 通知ID列表
     * @return 操作结果
     */
    @DeleteMapping("/batch")
    @SaCheckLogin
    public Result<String> batchDeleteNotifications(@RequestBody List<Long> notificationIds) {
        try {
            Long userId = StpUtil.getLoginIdAsLong();
            boolean success = notificationService.batchDeleteNotifications(notificationIds, userId);
            return success ? Result.success("批量删除成功") : Result.error("批量删除失败");
        } catch (Exception e) {
            log.error("批量删除通知失败", e);
            return Result.error("批量删除失败：" + e.getMessage());
        }
    }

    /**
     * 清空已读通知
     *
     * @return 操作结果
     */
    @DeleteMapping("/clear-read")
    @SaCheckLogin
    public Result<String> clearReadNotifications() {
        try {
            Long userId = StpUtil.getLoginIdAsLong();
            boolean success = notificationService.clearReadNotifications(userId);
            return success ? Result.success("清空成功") : Result.error("清空失败");
        } catch (Exception e) {
            log.error("清空已读通知失败", e);
            return Result.error("清空失败：" + e.getMessage());
        }
    }

    /**
     * 重新计算通知统计
     *
     * @return 操作结果
     */
    @PostMapping("/recalculate-stats")
    @SaCheckLogin
    public Result<String> recalculateStats() {
        try {
            Long userId = StpUtil.getLoginIdAsLong();
            boolean success = notificationService.recalculateUserNotificationStats(userId);
            return success ? Result.success("重新计算成功") : Result.error("重新计算失败");
        } catch (Exception e) {
            log.error("重新计算通知统计失败", e);
            return Result.error("重新计算失败：" + e.getMessage());
        }
    }

    /**
     * 分页查询聚合通知列表（只聚合LIKE、FOLLOW、COLLECT类型）
     * 
     * <p>聚合策略：</p>
     * <ul>
     *   <li>点赞（LIKE）- 聚合显示，例："张三、李四等15人赞了你的文章"</li>
     *   <li>关注（FOLLOW）- 聚合显示，例："张三、李四等5人关注了你"</li>
     *   <li>收藏（COLLECT）- 聚合显示，例："张三、李四等8人收藏了你的文章"</li>
     * </ul>
     * 
     * <p>不聚合类型（使用普通列表接口）：</p>
     * <ul>
     *   <li>评论（COMMENT）- 每条内容不同，不适合聚合</li>
     *   <li>回复（REPLY）- 需要看到对话上下文</li>
     *   <li>@提及（MENTION）- 需要看到具体提及内容</li>
     * </ul>
     *
     * @param query 查询条件
     * @return 聚合通知分页列表（只包含LIKE、FOLLOW、COLLECT类型）
     */
    @GetMapping("/grouped")
    @SaCheckLogin
    public Result<IPage<NotificationGroupResponse>> getGroupedNotificationList(@Valid NotificationQueryRequest query) {
        try {
            Long userId = StpUtil.getLoginIdAsLong();
            IPage<NotificationGroupResponse> page = notificationService.getGroupedNotificationPage(userId, query);
            return Result.success("查询成功", page);
        } catch (Exception e) {
            log.error("查询聚合通知列表失败", e);
            return Result.error("查询失败：" + e.getMessage());
        }
    }

    /**
     * 获取指定分组的通知详情列表
     *
     * @param type 通知类型
     * @param targetType 目标类型
     * @param targetId 目标ID
     * @return 通知详情列表
     */
    @GetMapping("/grouped/details")
    @SaCheckLogin
    public Result<List<NotificationResponse>> getGroupedNotificationDetails(
            @RequestParam String type,
            @RequestParam(required = false) String targetType,
            @RequestParam(required = false) Long targetId) {
        try {
            Long userId = StpUtil.getLoginIdAsLong();
            List<NotificationResponse> details = notificationService.getGroupedNotificationDetails(
                userId, type, targetType, targetId
            );
            return Result.success("查询成功", details);
        } catch (Exception e) {
            log.error("获取分组通知详情失败", e);
            return Result.error("查询失败：" + e.getMessage());
        }
    }

    /**
     * 标记指定分组的所有通知为已读
     *
     * @param type 通知类型
     * @param targetType 目标类型
     * @param targetId 目标ID
     * @return 操作结果
     */
    @PutMapping("/grouped/mark-read")
    @SaCheckLogin
    public Result<String> markGroupAsRead(
            @RequestParam String type,
            @RequestParam(required = false) String targetType,
            @RequestParam(required = false) Long targetId) {
        try {
            Long userId = StpUtil.getLoginIdAsLong();
            boolean success = notificationService.markGroupAsRead(userId, type, targetType, targetId);
            return success ? Result.success("标记成功") : Result.error("标记失败");
        } catch (Exception e) {
            log.error("标记分组通知为已读失败", e);
            return Result.error("标记失败：" + e.getMessage());
        }
    }
}

